import ujson
from peewee import DoesNotExist
from fastapi.encoders import jsonable_encoder

from common.g.g import G_LOGGER
from common.utils.resp import RC
from common.v.v import DATAORCODE
from schema.req_schema.client_user_req_schema import AddNewClientUserRequestModel, ClientUserLoginRequestModel
from service.base import Service
from common.pkg.str_id import get_short_uuid
from common.model.user.client_user import ClientUser
from common.model.user.point import ClientUserPoint


class ClientUserPointService(Service):

    async def add_new_user_point(self, tenant_id, user_id):
        return await ClientUserPoint.add_new_instance(self.mgw, tenant_id=tenant_id, user_id=user_id)

    async def get_user_point(self, tenant_id, user_id):
        cache_key = f"tenant:{tenant_id}:user:{user_id}:point"
        cache_data = await self.cache.get_cache(cache_key)
        if cache_data:
            return True, DATAORCODE(data=ujson.loads(cache_data))
        try:
            res = await ClientUserPoint.get_instance(self.mgw, condition={"tenant_id": tenant_id, "user_id": user_id, "removed": False})
        except DoesNotExist:
            return False, DATAORCODE(data=None, code=RC.USER_NOT_EXIST, msg="用户不存在")
        await self.cache.set_cache(cache_key, ujson.dumps(jsonable_encoder(dict(res))), ex=30 * 60)
        return True, DATAORCODE(data=res)




class ClientUserService(Service):

    async def _is_phone_exist(self, tenant_id, phone):
        query = ClientUser.select(ClientUser.user_id).where(ClientUser.tenant_id == tenant_id,
                                                            ClientUser.phone == phone,
                                                            ClientUser.removed == False)
        return await self.mgw.execute(query)

    async def _is_email_exist(self, tenant_id, email):
        query = ClientUser.select(ClientUser.user_id).where(ClientUser.tenant_id == tenant_id,
                                                            ClientUser.email == email,
                                                            ClientUser.removed == False)
        return await self.mgw.execute(query)

    async def _is_user_exist_by_invite_code(self, tenant_id, invite_code):
        query = ClientUser.select(ClientUser.user_id).where(ClientUser.tenant_id == tenant_id,
                                                            ClientUser.invite_code == invite_code
                                                            )
        return await self.mgw.execute(query)

    async def register(self, user_model: AddNewClientUserRequestModel):
        if not user_model.invite_code:
            user_model.invite_code = get_short_uuid(prefix="I-")
        # 1. 判断手机号是否被注册
        # 2. 判断邮箱是否被注册
        # 3. 判断受邀码是否存在
        # 4 todo 获取租户的配置信息,对注册用户的隐私信息进行加密处理,对密码进行md5处理 TenantConfig
        assert user_model.tenant_id, "参数异常"

        tenant_id = user_model.tenant_id
        if user_model.phone:
            pe = await self._is_phone_exist(tenant_id, user_model.phone)
            if pe:
                return False, DATAORCODE(data=None, code=RC.PHONE_ALREADY_REGISTER, msg="手机号已经被注册")
        if user_model.email:
            ee = await self._is_email_exist(tenant_id, user_model.email)
            if ee:
                return False, DATAORCODE(data=None, code=RC.EMAIL_ALREADY_REGISTER, msg="邮箱已经被注册")
        if user_model.invited_code:
            ec = await self._is_user_exist_by_invite_code(tenant_id, user_model.invited_code)
            if ec:
                return False, DATAORCODE(data=None, code=RC.USER_NOT_EXIST, msg="邀请码错误")

        data = user_model.dict(exclude_unset=True, exclude_none=True)
        cups = ClientUserPointService(self.mgw, self.redis)
        async with self.mgw.atomic() as f:
            try:
                user_id = await ClientUser.add_new_instance(self.mgw, **data)
                await cups.add_new_user_point(tenant_id, user_id)
            except Exception as e:
                await f.rollback()
                G_LOGGER.exception(e)
                return False, DATAORCODE(data=None, code=RC.DB_ERROR, msg="服务异常")
            return True, DATAORCODE(data={"user_id": user_id})

    async def query_user_by_email_and_password(self, tenant_id, req: ClientUserLoginRequestModel):
        condition = {
            "tenant_id": tenant_id,
            "email": req.email,
            "password": req.password,
            "removed": False
        }
        try:
            user = await ClientUser.get_instance(self.mgw, condition=condition)
        except DoesNotExist:
            return False, DATAORCODE(data=None, code=RC.USER_NOT_EXIST, msg="邮箱或者密码错误")
        except Exception as e:
            G_LOGGER.exception(e)
            return False, DATAORCODE(data=None, code=RC.DB_ERROR, msg="服务异常")
        return True, DATAORCODE(data=user)

    async def get_user_by_id(self, tenant_id, user_id):
        cache_key = f"tenant:{tenant_id}:cli:user:{user_id}"
        cache_data = await self.cache.get_cache(cache_key)
        if cache_data:
            return True, DATAORCODE(data=ujson.loads(cache_data))
        try:
            data = await ClientUser.get_instance(self.mgw, condition={"tenant_id": tenant_id, "user_id": user_id, "removed": False})
        except DoesNotExist:
            return False, DATAORCODE(data=None, code=RC.USER_NOT_EXIST, msg="用户不存在")
        except Exception as e:
            G_LOGGER.exception(e)
            return False, DATAORCODE(data=None, code=RC.DB_ERROR, msg="服务异常")
        await self.cache.set_cache(cache_key, ujson.dumps(jsonable_encoder(dict(data))), ex=30 * 60)
        return True, DATAORCODE(data=data)





